在 JS30第二天的 JS & CSS Clock 中,我們利用Javascript中的 setInterval()
方法以及CSS屬性,在頁面上做出一個會轉動的虛擬時鐘。而在倒數第二天的課題當中,我們要做出一個倒數計時器。[1]
實作連結
在倒數計時器的頁面中我們包含了幾種功能:
在作者的草稿中,我們看到頁面上分成了 <button>
及 <form>
兩種輸入形式,而首先我們來處理 <button>
的部分。
<div class="timer">
<div class="timer__controls">
<button data-time="20" class="timer__button">20 Secs</button>
<button data-time="300" class="timer__button">Work 5</button>
<button data-time="900" class="timer__button">Quick 15</button>
<button data-time="1200" class="timer__button">Snack 20</button>
<button data-time="3600" class="timer__button">Lunch Break</button>
<form name="customForm" id="custom">
<input type="text" name="minutes" placeholder="Enter Minutes">
</form>
</div>
<div class="display">
<h1 class="display__time-left"></h1>
<p class="display__end-time"></p>
</div>
</div>
將我們需要的 DOM 元素選取起來之後,先將全部的 <button>
元素加上監聽事件 onclick
,並指定觸發時執行的函示:
const buttons = document.querySelectorAll('.timer__button');
const timeLeft = document.querySelector('.display__time-left');
const endTime = document.querySelector('.display__end-time');
const input = document.querySelector('form');
buttons.forEach(function (button) {
button.addEventListener('click', setTime);
});
而在執行的函示中我們需要完成幾件事情:
因此在觸發的函式當中,我們先取得倒數計時的時間長度與目前的時間,再透過指定參數給其他函式,完成後面三個功能,我們的程式碼的可讀性會比較高。
除此之外,因為會使用到 setInterval()
方法,我們先在全域環境下指定一個代表變數setInterval()
,方便我們後續使用 clearInterval()
方法,並且在執行的函式中先執行一次 clearInterval()
將先前的 setInterval()
方法先清除掉,避免 Bug 發生:
let count;
function setTime(event) {
//清除之前的 setInterval() 方法
clearInterval(count);
//取得按鍵中 data-attibute 中所代表的倒數計時時間並轉為數字
let remainTime = parseInt(this.dataset.time);
//取得目前的時間
let currentTime = new Date();
//執行顯示剩餘時間的函式
showRemainTime(remainTime);
//執行倒數計時的函式
countDown(remainTime);
//執行顯示結束時間的函式
showEndTime(currentTime, remainTime);
};
在顯示剩餘時間在頁面上的函式當中,我們要將時間轉換成我們想要的格式,並將這個字串內容指定為 <.display__time-left
> 元素的 innerHTML
內容。
可以看到我們將分別代表時、分、秒的參數加上一判斷式,當該值小於零,我們就將其值修改為兩個數字的型態,如此一來就能讓顯示的字串一直維持類似電子錶的格式:
function showRemainTime(time) {
//利用 parseInt 取得小時的整數
let hour = parseInt(time / 3600);
if (hour < 10) {
hour = `0${hour}`;
}
//利用 parseInt 取得分鐘的整數
let min = parseInt((time - hour * 3600) / 60);
if (min < 10) {
min = `0${min}`;
}
//利用 % 取得秒數
let sec = time % 60;
if (sec < 10) {
sec = `0${sec}`;
}
let text = `${hour}:${min}:${sec}`;
//指定顯示剩餘時間元素的 innerHTML
timeLeft.innerHTML = text;
//指定頁面標題
document.title = text;
};
在執行倒數計時的函式中,我們要透過 setInterval()
方法,每秒將倒數剩餘時間減去一秒,並且將新的剩餘時間,重新印到頁面上。除此之外當剩餘為0時,我們要移除該 setInterval()
方法,因此在此執行函式當中,我們要透過判斷式來幫助我們執行:
function countDown(remainTime) {
//將變數 count 指定為 每秒執行一次的 setInterval() 函式
count = setInterval(function () {
//當剩餘時間 > 0,將剩餘時間減去一秒,並重新顯示在頁面上
if (remainTime > 0) {
remainTime--;
showRemainTime(remainTime)
//當剩餘時間 =< 0,清除 setInterval() 函式
} else {
clearInterval(count);
}
}, 1000)
};
最後是顯示結束時間的函式。在此函式當中,我們已經利用參數,取得剛開始觸發事件時,倒數計時總時間與當下的時間,而我只要將當下的時間轉為秒數,再透過換算成小時、分鐘、秒,最後再指派給 <.display__end-time>
元素的 innerHTML
內容:
function showEndTime(currentTime, remainTime) {
//取得目前時間的時、分、秒
let currentHour = currentTime.getHours();
let currentMin = currentTime.getMinutes();
let currentSec = currentTime.getSeconds();
//結束時間為目前的時間加上倒數時間總長度
let predictTime = remainTime + currentHour * 3600 + currentMin * 60 + currentSec;
//換算結束時間的小時
let predictHour = parseInt(predictTime / 3600);
if (predictHour < 10) {
predictHour = `0${predictHour}`;
}
//換算結束時間的分鐘
let predictMin = parseInt((predictTime - predictHour * 3600) / 60);
if (predictMin < 10) {
predictMin = `0${predictMin}`;
}
//換算結束時間的秒鐘
let predictSec = predictTime % 60;
if (predictSec < 10) {
predictSec = `0${predictSec}`;
}
//指定顯示結束時間元素的 innerHTML
endTime.innerHTML = `${predictHour % 24}:${predictMin}:${predictSec}`;
};
基本的功能我們已經完成,再來只要將 <form>
元素中的 <input>
數值指派給倒數計時功能即可完成,而為了避免輸入的字不是數字,我們在判斷是中加上 isNaN()
方法來幫助我們判斷是否為數字。
而在之前的章節中有提過,<form>
元素觸發 onsubmit
事件時,頁面會被重整,因此需要先加上 event.preventDefault()
方法來避免:
input.addEventListener('submit', setInputTime);
function setInputTime(event) {
event.preventDefault();
//取得 form 容器中的 input 子元素嶿入的資料
let inputValue = this.querySelector('input').value;
if (isNaN(inputValue)) {
window.alert('請輸入數字!!')
} else {
clearInterval(count);
let remainTime = inputValue * 60;
let currentTime = new Date();
countDown(remainTime);
showRemainTime(remainTime);
showEndTime(currentTime, remainTime);
}
this.reset();
};
完成以上的程式碼之後,就能完成今天的課題囉!!
在倒數第二天的內容當中,我們重新複習了 setInterval()
方法與 new Date ()
物件,並將他們組合起來做出倒數計時器。透過這兩種技能,相信我們能做出更多跟時間有關的有趣小工具!